package online.sixfish.question.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import online.sixfish.common.eunmration.UserQueProgramRelationshipEnum;
import online.sixfish.question.model.Question;
import online.sixfish.question.service.QueProgramService;
import online.sixfish.common.dto.PageDTO;
import online.sixfish.common.exception.CommonConstant;
import online.sixfish.question.mapper.QueProgramMapper;
import online.sixfish.question.model.entity.QueProgram;
import online.sixfish.question.service.UserQuestionRelationShipService;
import online.sixfish.question.utils.XmlUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Objects;

@Slf4j
@Service
public class QueProgramServiceImpl implements QueProgramService {

    @Resource
    QueProgramMapper queProgramMapper;

    @Resource
    UserQuestionRelationShipService userQuestionRelationShipService;

    @Override
    public PageDTO<QueProgram> list(Integer pageNum, Integer pageSize, Integer difficulty, Integer userQueStatus) {

        LambdaQueryWrapper<QueProgram> wrapper = new LambdaQueryWrapper<>();
        wrapper.ne(QueProgram::getStatus, CommonConstant.SYS_ILLEGAL_STATUS);
        if (Objects.nonNull(difficulty)) {
            wrapper.eq(QueProgram::getDifficulty, difficulty);
        }
        //用户解题状态
        if (Objects.nonNull(userQueStatus)) {
            Map<Integer, List<Integer>> relation = userQuestionRelationShipService
                    .getUserQueProgramRelation();
            List<Integer> triedlist = relation.get(UserQueProgramRelationshipEnum.TRIED.getId());
            List<Integer> solvedList = relation.get(UserQueProgramRelationshipEnum.SOLVED.getId());
            //未开始的状态 排除已经存在的
            if (Objects.equals(userQueStatus,
                    UserQueProgramRelationshipEnum.NOT_STARTED.getId())) {
                for (Integer i : triedlist
                ) {
                    wrapper.ne(QueProgram::getId, i);
                }
                for (Integer i : solvedList
                ) {
                    wrapper.ne(QueProgram::getId, i);
                }

            } else if (Objects.equals(userQueStatus,
                    UserQueProgramRelationshipEnum.TRIED.getId())) {
                if (CollectionUtils.isEmpty(triedlist)) {
                    return PageDTO.emptyPageDTO();
                }
                wrapper.in(QueProgram::getId, triedlist);
            } else if (Objects.equals(userQueStatus,
                    UserQueProgramRelationshipEnum.SOLVED.getId())) {
                if (CollectionUtils.isEmpty(solvedList)) {
                    return PageDTO.emptyPageDTO();
                }
                wrapper.in(QueProgram::getId, solvedList);
            }
        }


        Page<QueProgram> page = new Page<>(pageNum, pageSize);
        Page<QueProgram> queProgramPage = queProgramMapper.selectPage(page, wrapper);
        PageDTO<QueProgram> pageDTO = PageDTO.build(queProgramPage);
        return pageDTO;
    }

    @Override
    public QueProgram getById(Integer id) {
        return queProgramMapper.selectById(id);
    }

    @Override
    public Integer getTotal() {
        LambdaQueryWrapper<QueProgram> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(QueProgram::getStatus, 1);
        return queProgramMapper.selectCount(wrapper);
    }

    @Override
    public void upload(MultipartFile file) throws IOException {
        Question question = XmlUtils.parseXml(file);
        log.info("question:{}", question);
        QueProgram program = copyProperties(question);
        log.info("添加编程题目：{}", program);
        queProgramMapper.insert(program);
    }

    @Override
    public PageDTO<QueProgram> select(Integer difficulty, Integer sortType, String name, Integer pageNum, Integer pageSize) {
        LambdaQueryWrapper<QueProgram> wrapper = new LambdaQueryWrapper<>();
        if (Objects.nonNull(difficulty)) {
            wrapper.eq(QueProgram::getDifficulty, difficulty);
        }
        if (Objects.nonNull(sortType)) {
            //1. 按尝试次数降序
            if ("1".equals(sortType)) {
                wrapper.orderByDesc(QueProgram::getTotalAttempt);
            } else if ("2".equals(sortType)) {
                wrapper.orderByDesc(QueProgram::getTotalPass);
            }
        }
        if (StringUtils.isNotBlank(name)) {
            wrapper.like(QueProgram::getName, name);
        }
        wrapper.ne(QueProgram::getStatus, CommonConstant.SYS_ILLEGAL_STATUS);
        Page<QueProgram> page = new Page<>(pageNum, pageSize);
        Page<QueProgram> queProgramPage = queProgramMapper.selectPage(page, wrapper);
        PageDTO<QueProgram> pageDTO = PageDTO.build(queProgramPage);
        return pageDTO;
    }

    @Override
    public void delete(Integer id) {
        QueProgram program = new QueProgram();
        program.setId(id);
        program.setStatus(CommonConstant.SYS_ILLEGAL_STATUS);
        queProgramMapper.updateById(program);
    }

    private QueProgram copyProperties(Question question) {
        QueProgram program = new QueProgram();
        program.setName(question.getQuestionName());
        program.setInputStyle(question.getInputStyle());
        program.setOutputStyle(question.getOutputStyle());
        program.setOutputSample(question.getOutputSample());
        program.setDataRange(question.getDataRange());
        program.setDifficulty(Integer.valueOf(question.getDifficulty()));
        program.setTimeLimit(question.getTimeLimit());
        program.setMemoryLimit(question.getMemoryLimit());
        program.setDescription(question.getDescription());
        program.setTag(question.getTag());
        program.setResource(question.getResource());
        program.setInputSample(question.getInputSample());
        program.setInputSampleData(
                question.getTestSamples().getSampleInput()
        );
        program.setOutputSampleData(
                question.getTestSamples().getSampleOutput()
        );
        program.setTotalAttempt(0);
        program.setTotalPass(0);
        return program;
    }
}
